/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Devices.Switches;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import moonnms.libs.interfaces.NMSSwitchContext;
import moonnms.libs.libNMSMacAddrTable;
import moonnms.libs.libNMSTools;
/**
 *
 * @author Di_Moon
 */
public class dlinkDxSGeneric extends NMSSwitchContext {
    protected dlinkTelnetClient telnet = null;          // Класс для связи по telnet

    static public int telnetPort = 23;
    
    protected String deviceName = null;
    protected String firmwareVersion = null;
    protected String hardwareVersion = null;
    protected String serialNumber = null;
    protected String systemLocation = null;
    protected String systemName = null;
    protected String deviceConfig = null;
    
    public dlinkDxSGeneric(String addr) {
        super(addr);
        
        telnet = new dlinkTelnetClient(addr, telnetPort);
    }
    
    protected boolean telnetConnect() {
        boolean result = telnet.connect();
        if(result) return telnet.login(user, pass);
        return result;
    }
            
    protected String cmdShSwitchParser(String data, String property) {
        Matcher matcher = Pattern.compile("("+property+")(.*):\\s(.*)").matcher(data);
        if(matcher.find()) return matcher.group(3);
        
        return null;
    }
    
    protected void getSystemInfoFromDevice() {
        String _data = null;
        if(telnetConnect()) {
              _data = telnet.sendCommand("show switch");
              telnet.disconnect();
        }
        
        if(_data != null) {
            deviceName      = cmdShSwitchParser(_data, "Device Type");
            firmwareVersion = cmdShSwitchParser(_data, "Firmware Version");
            hardwareVersion = cmdShSwitchParser(_data, "Hardware Version");
            serialNumber    = cmdShSwitchParser(_data, "Serial Number");
            systemLocation  = cmdShSwitchParser(_data, "System Location");
            systemName      = cmdShSwitchParser(_data, "System Name");
        }        
    }

    @Override
    public libNMSMacAddrTable getMacAddressTable() {
        HashMap<String, String> fdb = snmp_ro.walk(".1.3.6.1.2.1.17.7.1.2.2.1.2");
        
        libNMSMacAddrTable table = new libNMSMacAddrTable();
        
        for(Entry<String, String> entry : fdb.entrySet()) {
            Matcher matcher = Pattern.compile("([0-9]*).([0-9]*).([0-9]*).([0-9]*).([0-9]*).([0-9]*).([0-9]*)$").matcher(entry.getKey());
            if(matcher.find()) {
                StringBuilder sb = new StringBuilder();
                int vlan = Integer.parseInt(matcher.group(1));
                int port = Integer.parseInt(entry.getValue());
                for(int i=2; i<=7; i++) {
                    sb.append(String.format("%02x:", (0xFF & Integer.parseInt(matcher.group(i)))));
                }
                sb.deleteCharAt(sb.length()-1);
                table.put(sb.toString(), port, vlan);
            }
            
        }
        
        return table;
    }

    @Override
    public String getDeviceName() {
        if(deviceName == null) getSystemInfoFromDevice();        
        return deviceName;
    }

    @Override
    public String getFirmwareVersion() {
        if(firmwareVersion == null) getSystemInfoFromDevice();        
        return firmwareVersion;
    }

    @Override
    public String getSerialNumber() {
        if(serialNumber == null) getSystemInfoFromDevice();
        return serialNumber;
    }

    @Override
    public String getSysLocation() {
        if(systemLocation == null) getSystemInfoFromDevice();
        return systemLocation;
    }

    @Override
    public void setSysLocation(String sysLocation) {
        snmp_rw.setString(".1.3.6.1.2.1.1.6.0", sysLocation);
        systemLocation = sysLocation;
    }

    @Override
    public String getConfiguration() {
        if(deviceConfig != null) return deviceConfig;
        
        if(telnetConnect()) {
              deviceConfig = telnet.sendCommand("show config current_config");
              telnet.disconnect();
        }
        return deviceConfig;
    }

    @Override
    public String getHardwareVersion() {
        if(hardwareVersion == null) getSystemInfoFromDevice();
        return hardwareVersion;
    }

    @Override
    public String getSystemName() {
        if(systemName == null) getSystemInfoFromDevice();
        return systemName;
    }

    @Override
    public void setSystemName(String sysName) {
        snmp_rw.setString(".1.3.6.1.2.1.1.5.0", sysName);
        systemName = sysName;
    }

    @Override
    public HashMap<Integer, String> getVlanTable() {
        if(!snmp) return null;
        
        HashMap<Integer, String> retVal = new HashMap<>();
        
        String oid = ".1.3.6.1.2.1.17.7.1.4.3.1.1";
        HashMap<String, String> walk = snmp_ro.walk(oid);        
//        System.out.println(walk);
        for(Entry<String, String> entry : walk.entrySet()) {
            String vlanName = entry.getValue();
            int vlanNum = 0;
            
            Matcher matcher = Pattern.compile("([0-9]+)$").matcher(entry.getKey());
            if(matcher.find()) vlanNum = Integer.parseInt(matcher.group(0));
            
            if(vlanNum > 0) {
//                System.out.println(vlanNum+" = "+vlanName);
                retVal.put(vlanNum, vlanName);
            }
        }
        
        if(!retVal.isEmpty()) return retVal;
        
        return null;
    }

    @Override
    public boolean setVlan(int vlNum, String vlName, HashMap<Integer, Integer> vlPorts) {
        // Добавляем vlan. Если vlan уже был и будет ошибка - её игнорируем
        snmp_rw.setInt(".1.3.6.1.2.1.17.7.1.4.3.1.5."+vlNum, 4);
        
        // Устанавливаем имя vlan
        snmp_rw.setString(".1.3.6.1.2.1.17.7.1.4.3.1.1."+vlNum, vlName);
        
        // Получим pattern для порт-листа
        String portPattern = snmp_ro.getString(".1.3.6.1.2.1.17.7.1.4.3.1.2."+vlNum);
        
        // Сформируем запросы на добавление влана на порты коммутатора
        int maxPort = libNMSTools.hashmap_GetMaxIndex(vlPorts);
        ArrayList vlanPorts = new ArrayList(Collections.nCopies(maxPort, 0));
        ArrayList vlanPortsUntagged = new ArrayList(Collections.nCopies(maxPort, 0));
        
        for(Entry<Integer, Integer> entry : vlPorts.entrySet()) {
            int port = entry.getKey()-1;
            int portType = entry.getValue();
            
            vlanPorts.set(port, 1);
            if(portType == VLAN_PORT_UNTAGGED) vlanPortsUntagged.set(port, 1);
        }

//        System.out.println("convert="+libNMSTools.sw_ConvertPortListToHex(vlanPorts, portPattern));
//        System.out.println("convert_untagged="+libNMSTools.sw_ConvertPortListToHex(vlanPortsUntagged, portPattern));

        String hex_vlanPorts = libNMSTools.sw_ConvertPortListToHex(vlanPorts, portPattern);
        String hex_vlanPortsUntagged = libNMSTools.sw_ConvertPortListToHex(vlanPortsUntagged, portPattern);
        
        // Проверим, что hex сформировался и ошибок не было
        if(hex_vlanPorts == null) return false;
        if(hex_vlanPortsUntagged == null) return false;
        
        // Отправляем на каких портах наш влан присутсвует
        snmp_rw.setHex(".1.3.6.1.2.1.17.7.1.4.3.1.2."+vlNum, hex_vlanPorts);
        // отправляем на каких портах наш влан не тегерирован
        snmp_rw.setHex(".1.3.6.1.2.1.17.7.1.4.3.1.4."+vlNum, hex_vlanPortsUntagged);
        
        return true;
    }

    @Override
    public HashMap<Integer, Integer> getVlanPort(int vlNum) {
        if(!snmp) return null;

        // Получим список портов, на которых присутсвует vlan
        String oid = ".1.3.6.1.2.1.17.7.1.4.3.1.2."+vlNum;
        String portsHex = snmp_ro.getString(oid);
        
        HashMap<Integer, Integer> retVal = new HashMap();
        
//        System.out.println(portsHex);
        int octet = 0;
        
        for(String hex : portsHex.split(":")) {
            ArrayList<Integer> portsList = libNMSTools.sw_GetPortsFromHex(hex);
            for(int i=0; i<portsList.size();i++) {
                if(portsList.get(i) == 1) {
                    int port = octet+(i+1);
                     retVal.put(port, VLAN_PORT_TAGGED);
                }
            }
            octet += 8;
        }
        
        // Получим список портов, на которых vlan в не тегерированном виде
        oid = ".1.3.6.1.2.1.17.7.1.4.3.1.4."+vlNum;
        portsHex = snmp_ro.getString(oid);
        octet = 0;
        for(String hex : portsHex.split(":")) {
            ArrayList<Integer> portsList = libNMSTools.sw_GetPortsFromHex(hex);
            for(int i=0; i<portsList.size();i++) {
                if(portsList.get(i) == 1) {
                    int port = octet+(i+1);
                     retVal.put(port, VLAN_PORT_UNTAGGED);
                }
            }
            octet += 8;
        }
        
        return retVal;
    }

    @Override
    public String getSystemContact() {
        return snmp_ro.getString(".1.3.6.1.2.1.1.4.0");
    }

    @Override
    public void setSystemContact(String sysContact) {
        snmp_rw.setString(".1.3.6.1.2.1.1.4.0", sysContact);
    }

    @Override
    public String getPortDescription(int portNum) {
        return snmp_ro.getString(".1.3.6.1.2.1.31.1.1.1.18."+portNum);
    }

    @Override
    public void setPortDescription(int portNum, String description) {
        snmp_rw.setString(".1.3.6.1.2.1.31.1.1.1.18."+portNum, description);
    }

    @Override
    public int getPortOperStatus(int portNum) {
        return snmp_ro.getInt(".1.3.6.1.2.1.2.2.1.8."+portNum);
    }

    @Override
    public long getPortOutOctets(int portNum) {
        return snmp_ro.getLong(".1.3.6.1.2.1.2.2.1.16."+portNum);
    }

    @Override
    public long getPortInOctets(int portNum) {
        return snmp_ro.getLong(".1.3.6.1.2.1.2.2.1.10."+portNum);
    }

    @Override
    public HashMap<Integer, String> getPortsList(int portsType) {
        HashMap<Integer, String> retVal = new HashMap();
        
        HashMap<String, String> portsList = snmp_ro.walk(".1.3.6.1.2.1.2.2.1.3");
        
        for(Entry<String, String> entry : portsList.entrySet()) {
            if((Integer.parseInt(entry.getValue())==portsType)||
                    (portsType==PORT_TYPE_ALL)) {
                Matcher matcher = Pattern.compile("([0-9]+)$").matcher(entry.getKey());
                if(matcher.find()) {
                    int portNum = Integer.parseInt(matcher.group(0));
                    String descr = snmp_ro.getString(".1.3.6.1.2.1.2.2.1.2."+portNum);
                    retVal.put(portNum, descr);
                }
            }
        }
        
        return retVal;
    }

    @Override
    public void deleteVlan(int vlNum) {
        snmp_rw.setInt(".1.3.6.1.2.1.17.7.1.4.3.1.5."+vlNum, 6);
    }
    
}
